零停机 schema 迁移:expand 之后为什么不能马上删旧列
直接改名或先删旧列,会让滚动部署中的旧实例当场失败。零停机迁移是"先扩展兼容、再回填切换、最后收缩"的状态机,每一步有守卫条件和回退边界。迁移状态机的完整形式化见数据契约、时间语义与重建;MySQL Online DDL 的引擎行为由 MySQL 主题权威讲授。
expand—migrate—contract的可回退边界
Expand-and-contract 先增加兼容结构和读写能力,再回填并验证,逐步切换读取,最后在所有旧消费者退出后删除旧结构。步骤间需要应用版本共存窗口。将name拆为given_name和family_name时,先增加新字段且旧版本仍可读写,再回填并建立兼容读路径,切换读写后观察,最后在旧代码与事件均退出后删旧字段。"零停机"不表示无锁、无资源成本或任意时刻都能回滚。
MySQL8.0不同DDL有INSTANT、INPLACE、COPY等路径及限制,元数据锁仍需考虑;具体操作按官方Online DDL矩阵核对,不凭"online"标签假设整张大表不会阻塞。
回填与前台写的竞争
t0回填读旧name;t1用户修改并写新字段;t2回填按旧快照覆盖。用对象版本/更新时间条件、幂等转换或从一致位置重建,不能无条件UPDATE。若新旧字段都允许独立修改,需一个权威写协议,否则双写成功也可能语义冲突。
1000万行、每批1000、每秒2批,纯处理5000秒约83分钟;每批锁与索引维护、binlog、复制滞后和失败重试会增加。限制复制落后/锁等待触发自动暂停,批量推进以持久游标为准,断点续跑不重复破坏数据。
双写存在一侧成功另一侧失败的窗口,需持久化差异并重试;事务写出 Outbox 可管理数据库内部变更对事件的发出。直接应用层双写不构成原子迁移。Outbox 协议由 Outbox、事务消息、最终一致性权威讲授。
两个方案和切换验收
方案A数据库新增列与应用双读兼容,运维简单但增加临时存储与写路径;方案B新表/新索引快照加CDC,隔离旧结构但引入日志水位、校验与切路由。根据数据量、写速率、DDL支持和回退窗口比较,不能一律用影子表。
发布旧客户端、新客户端与后台回填同时运行的测试矩阵。收集非法空值、业务汇总、schema兼容、慢查询与复制水位;切换后保留旧读/修复路径直到明确contract准入。删旧列之后回滚旧二进制不再安全,应前向修复。切流前后要比对行数、摘要、关键聚合和错误率;校验必须考虑复制延迟与写入持续发生。
按聚合边界安排迁移顺序
本页前面把迁移写成 expand-migrate-contract 状态机,但没有回答"多上下文系统里,先迁哪个"。答案是按聚合边界排序:先聚合内的结构,再跨上下文的契约,最后删除;每一步都用聚合不变量复验。
顺序的理由:聚合内结构变化只影响一个上下文,回滚面小;跨上下文契约变化影响所有消费者,需要发布窗口与兼容测试;删除共享结构不可逆,必须等所有消费者退出。把顺序颠倒——先删共享列——就是本页开头"expand 之后为什么不能马上删旧列"的多上下文版本:内部消费者可能已升级,外部消费者还没升级,删除直接造成破坏。
每阶段的守卫条件要能执行:"聚合内结构就绪"意味着新字段已回填、聚合守卫在新旧两条写路径上都通过;"契约就绪"意味着集成事件的新版本已发布,全部消费者声明兼容;"允许删除"意味着旧字段无写入、无读取、无事件引用。守卫不是文档描述,而是发布流水线里的检查项。
执行 python3 labs/context_model.py all:其中 migration-order 模型按"聚合→契约→删除"推进,每阶段读取就绪标志;all 末尾另跑一个独立阴性对照 migration-order-blocked,验证契约未就绪时删除阶段被阻断(contract_ok=false、drop_allowed=false)。单独运行 migration_order 只输出正向阶段与错误顺序反例,不含该阴性对照。同时给出错误顺序的反例:先删共享列,三个阶段累计 3 处违规。脚本是规则检查,不执行真实 DDL。
两个合理选择:A 按表迁移,逐表 expand/contract,简单但可能打断聚合不变量(一个聚合横跨两张表时中途状态不合法);B 按聚合迁移,先保证聚合整体可写可读,再动跨上下文契约。本例选 B,并把聚合不变量写成迁移流水线的断言——只要有一阶段不变量不成立,流水线停止而不是"先上线再说"。
架构师变化条件
把回填窗口从 83 分钟压缩到 20 分钟:批次速率提高四倍,锁、binlog 与复制滞后预算同步放大,需评估自动暂停阈值而不是硬推。若旧字段被外部系统导出依赖,contract 阶段要等外部下线证据,不能只看内部消费者。新字段允许旧模型无法表达的状态(如三段姓名、多值)时,回滚从"切回旧二进制"变为"前向修复+双版本读窗口"——回滚代码与回滚数据是两个决定。
闭卷验收
本页 8 道闭卷题收进了下方自测面板:先回忆,再展开参考答案与评分点,最后给三档自评。